#pragma once
#pragma managed
//////////////////////////////////////////////////////////////////////////
using namespace System;
//////////////////////////////////////////////////////////////////////////
NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////
public interface class INativeHandleObject
{
	IntPtr ToPointer();
};

public ref class NativeHandleObject abstract : public INativeHandleObject
{
public:
	static bool IsNullOrInvalid(NativeHandleObject^ object)
	{
		return object == nullptr || !object->IsValid;
	}

protected:
	NativeHandleObject(bool own) : m_bOwnTheHandle(own), m_pHandle(NULL)
	{

	}

	NativeHandleObject(void* handle, bool own) : m_bOwnTheHandle(own), m_pHandle(handle)
	{

	}

	virtual ~NativeHandleObject()
	{
		if (m_bOwnTheHandle && m_pHandle != NULL)
		{
			this->ReleaseHandle();
		}
		m_pHandle = NULL;
	}

public:
	virtual IntPtr ToPointer() 
	{
		return IntPtr(m_pHandle); 
	}

	virtual int CompareTo(NativeHandleObject^ obj)
	{
		return obj->m_pHandle == this->m_pHandle ? 0 : 
			(obj->m_pHandle > this->m_pHandle) ? 1 : -1;
	}

	void Attach(IntPtr handle)
	{
		Attach(handle.ToPointer());
	}

	IntPtr Detach()
	{
		void* handle = m_pHandle;
		m_pHandle = NULL;
		return IntPtr(handle);
	}

	property bool IsValid
	{
		bool get()
		{
			return m_pHandle != NULL;
		}
	}

protected:

	virtual void ReleaseHandle() abstract;
	void Attach(void* handle)
	{
		if (m_bOwnTheHandle && m_pHandle != NULL)
		{
			this->ReleaseHandle();
		}
		m_pHandle = handle;
	}

internal:
	inline void* ToNativePointer()
	{
		return m_pHandle;
	}

	void* m_pHandle;

private:
	bool m_bOwnTheHandle;
};
//////////////////////////////////////////////////////////////////////////
NAMESPACE_END
//////////////////////////////////////////////////////////////////////////